<html>
<head>
<title>How to script with Ruby and Zeitgeist</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" href="highlight.css" type="text/css">
</head>

<body bgcolor="#FFFFFF" text="#000000">
<p><font size="6"><i><b>How to script with Ruby and Zeitgeist</b></i></font></p>
<p align="left"><font size="4">A lot of the flexibility of the software system 
  provided in this diploma thesis comes from the ability to perform a lot of operations 
  through scripts. The system uses the scripting language <a href="http://www.ruby-lang.org/en/">Ruby</a>. 
  In this HowTo we will learn how to execute scripts and we will meet a few built-in 
  scripting commands for interaction with the object hierarchy.</font></p>
<p align="left"><font size="4"><b><font size="5">Executing Scripts</font></b></font></p>
<p align="left"><font size="4">The task of executing scripts is rather easy. It 
  is done using a built-in class of Zeitgeist ... the ScriptServer. The ScriptServer 
  is located in the object hierarchy at the position '/sys/server/script'. Using 
  a CoreContext, we can access an object in the hierarchy. We retrieve the instance 
  of the ScriptServer and then use it to execute a Ruby script:</font></p>
<pre><span class="dir">#include &lt;zeitgeist/zeitgeist.h&gt;
</span>
<span class="key">using namespace </span>boost;
<span class="key">using namespace </span>zeitgeist;

<span class="typ">int </span>main()
{
  Zeitgeist  zeitgeist;

  shared_ptr&lt;CoreContext&gt; context = zeitgeist.CreateContext();
  
  shared_ptr&lt;ScriptServer&gt; scriptServer = shared_static_cast&lt;ScriptServer&gt;(context-&gt;Get(<span class="str">&quot;/sys/server/script&quot;</span>));
 
  scriptServer-&gt;Run(<span class="str">&quot;scripttest.rb&quot;</span>);
  
  <span class="key">return </span><span class="num">0</span>;
}
</pre>
<p align="left"><font size="4">As the above program shows, the entire system relies 
  heavily on the <a href="http://www.boost.org">Boost library</a> and its smart 
  pointer facilities. This makes every object reference counted and ensures safe 
  object deletion. Due to the template nature it does make a few code lines longer 
  than usually necessary, but the added safety is worth it. The example above 
  should be self-explanatory. We create the Zeitgeist object. This creates the 
  object hierarchy and the built-in services (ScriptServer, LogServer and FileServer). 
  Then, we create a context. This is necessary, because everytime we specify a 
  path, we can specify a relative path. Thus, we need a position in the object 
  hierarchy we need to be relative to ... this is provided by the CoreContext. 
  Using it, we retrieve the ScriptServer instance and execute a script through 
  it.</font></p>
<p align="left"><font size="4"><b><font size="5">Builtin Script Commands</font></b></font></p>
<p align="left"><font size="4">The ScriptServer has its own CoreContext associated 
  with it. So, every script command can be considered to be executed at a specific 
  location in a virtual file system. Basically, the scripts are run inside a 'shell'. 
  Now, let's take a look at the builtin commands:</font></p>
<p align="left"><font size="4"><b>importBundle (string path)</b></font></p>
<p align="left"><font size="4">This command is analogous to calling ImportBundle() 
  on the Core object. It takes a string as a parameter, which should be the location 
  of a DLL containing a valid entry point function.</font></p>
<p align="left"><font size="4"><b>selectObject (string path) / cd (string path)</b></font></p>
<p align="left"><font size="4"> The actual name of the command is selectObject, 
  but an alias to cd is provided. This command makes it possible to navigate the 
  object hierarchy. It works similar to its command shell counterpart, except 
  that the path always has to be given in the form of a string. This function 
  accepts absolute and relative paths. It changes what I call the 'current working 
  object' or the 'current selected object'. </font></p>
<p align="left"><font size="4"><b>ls</b></font></p>
<p align="left"><font size="4">This command lists the contents of the current 
  working object.</font></p>
<p align="left"><font size="4"><b>pushd</b></font></p>
<p align="left"><font size="4">This command pushes the current working object 
  on a stack for later use. This is extremely helpful when building larger scene 
  graph hierarchies.</font></p>
<p align="left"><font size="4"><b>popd</b></font></p>
<p align="left"><font size="4">Pops a current working object off the stack.</font></p>
<p align="left"><font size="4"><b>dirs</b></font></p>
<p align="left"><font size="4">Lists the stack of current working objects which 
  have been pushed via pushd.</font></p>
<p align="left"><font size="4"><b>new (string className, string path)</b></font></p>
<p align="left"><font size="4">This command creates instances of classes, names 
  them and places them at a certain location in the object hierarchy. The first 
  parameter is the name of the class to instantiate. This name is relative to 
  the '/classes/' object. The second parameter is the name and path of the object 
  to create. Some examples:</font></p>
<p align="left"><font size="4">new ('Simple', 'test');</font></p>
<p align="left"><font size="4">This creates an instance of the Simple class (/classes/Simple) 
  and gives it the name 'test'. It is created at the current location in the object 
  hierarchy. </font></p>
<p align="left"><font size="4">new ('Simple', 'blub/test');</font></p>
<p align="left"><font size="4">This creates an instance of the Simple class (/classes/Simple) 
  and gives it the name 'test'. It is created under a subdirectory of the current 
  location called 'blub' ... So if one would be located at the root directory 
  (/). The new instance of Simple would be located at '/blub/test'.</font></p>
<p align="left"><font size="4">It is also possible to specify namespace for class 
  names. For example, you create the FontServer of Kerosin like this:</font></p>
<p align="left"><font size="4">new ('kerosin/FontServer', '/sys/server/font');</font></p>
<p align="left"><font size="4">The new function returns a Ruby proxy object to 
  the created instance. The created instance is also made the current working 
  object!! How the proxies can be used to invoke C++ side functions is discussed 
  in the <a href="howto_function.html">next HowTo</a>.</font></p>
<p align="left"><font size="4"><b>get (string path)</b></font></p>
<p align="left"><font size="4">This command returns a Ruby proxy object of the 
  instance specified by the parameter 'path'. How the proxies can be used to invoke 
  C++ side functions is discussed in the <a href="howto_function.html">next HowTo</a>.</font></p>
<p align="left"><font size="4"><b>delete (string path)</b></font></p>
<p align="left"><font size="4">This command deletes an object (and its subobjects) 
  from the object hierarchy. It basically unlinks the object from the hierarchy. 
  This removes a reference. Only if no other references remain will the object 
  be deleted!!!!</font></p>
<p align="left"><font size="4">This already concludes our rundown of the builtin 
  scripting functions of Zeitgeist. We can now create and manipulate object hierarchies 
  with simple Ruby scripts. Some of the functions return a Ruby-side proxy object 
  to an instance in the object hierarchy. How the proxies can be used to invoke 
  C++ side functions and how to expose C++ side functions to the proxies is discussed 
  in the <a href="howto_function.html">next HowTo</a>.</font></p>
</body>
</html>

